package com.hulk.rpc.serialize;

import com.hulk.rpc.exception.HulkRpcException;
import com.hulk.rpc.param.MethodParam;
import com.hulk.rpc.param.MethodParamClassResolver;
import com.hulk.rpc.protocol.Request;
import com.hulk.rpc.protocol.Response;
import com.hulk.rpc.serialize.impl.kryo.KryoSerializer;
import com.hulk.rpc.serialize.impl.proto.ProtostuffSerializer;
import io.netty.buffer.ByteBuf;

import java.io.IOException;
import java.util.Map;

/**
 * @author xuxukang
 */
public abstract class Serializer {

  private MethodParamClassResolver methodParamClassResolver;

  public final void setClassResolver(MethodParamClassResolver methodParamClassResolver) {
    this.methodParamClassResolver = methodParamClassResolver;
  }

  public final Class<? extends MethodParam> getMethodParamClass(int serviceId) {
    return methodParamClassResolver.getMethodParamClass(serviceId);
  }

  public abstract void writeRequest(ByteBuf byteBuf, Request request) throws IOException;

  public abstract Request readRequest(ByteBuf byteBuf) throws IOException;

  public abstract void writeResponse(ByteBuf byteBuf, Response response) throws IOException;

  public abstract Response readResponse(ByteBuf byteBuf) throws IOException;

  /**
   * 是否支持classID
   */
  public boolean isSupportedClassId() {
    return false;
  }

  /**
   * 设置classID
   */
  public void setClassIds(Map<Class<?>, Integer> classIds) {
  }

  public enum SerializeEnum {
    proto(ProtostuffSerializer.class),
    kryo(KryoSerializer.class);

    private Class<? extends Serializer> serializerClass;

    SerializeEnum(Class<? extends Serializer> serializerClass) {
      this.serializerClass = serializerClass;
    }

    public Serializer getSerializer() {
      try {
        return serializerClass.getDeclaredConstructor().newInstance();
      } catch (Exception e) {
        throw new HulkRpcException("反射获取序列化器失败", e);
      }
    }

    public static SerializeEnum match(String name, SerializeEnum defaultSerializer) {
      for (SerializeEnum item : SerializeEnum.values()) {
        if (item.name().equals(name)) {
          return item;
        }
      }
      return defaultSerializer;
    }
  }

}
